package ${groupId}.controller.boss.login;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.Serializable;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

import javax.imageio.ImageIO;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootVersion;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import ${groupId}.controller.boss.login.dto.BossLoginForm;
import ${groupId}.service.security.SessionService;
import ${groupId}.service.security.authc.MallUsernamePasswordToken;
import ${groupId}.service.system.sysparam.SysParamService;

import com.system.core.controller.ControllerBase;
import com.system.core.utils.CaptchaUtils;
import com.system.core.utils.HttpUtils;

import lombok.extern.slf4j.Slf4j;
import io.swagger.v3.oas.annotations.Operation;

@Controller
@RequestMapping(value = "boss")
@Slf4j
public class LoginController extends ControllerBase{
	
	@Autowired
    private EhCacheManager ecm;
	
	@Autowired
	private Environment environment;
	
	@Autowired
	private SessionService sessionService;
	
	@Autowired
	private SysParamService sysParamService;
	
	private final String loginTemplate = "/login-layui";
	private final String mainTemplate = "/main";
	
	@GetMapping(value = "login")
	@Operation(hidden = true)
	public String login(BossLoginForm bossLoginForm) {
		if (SecurityUtils.getSubject().isRemembered()
				|| SecurityUtils.getSubject().isAuthenticated()) {
			return "redirect:/boss/main";
		}
		getModelMap().addAttribute("loginForm", bossLoginForm);
		getModelMap().addAttribute("boss_title",sysParamService.getString("boss_title"));
		getModelMap().addAttribute("boss_sub_title",sysParamService.getString("boss_sub_title"));
		getModelMap().put("springBootVersion", SpringBootVersion.getVersion());
		return "boss"+loginTemplate;
	}

	@RequestMapping(value = "login",method = RequestMethod.POST)
	public String login(@Validated @ModelAttribute(name = "loginForm") BossLoginForm loginForm, BindingResult result) {
		log.info("[登录]入参：{}",loginForm);
		if (SecurityUtils.getSubject().isAuthenticated()) {
			return "redirect:/"+loginForm.getLoginType()+mainTemplate;
        }
		if (result.hasErrors()) {
            loginForm.reset();
            return loginForm.getLoginType()+loginTemplate;
        }
		try {
            MallUsernamePasswordToken token = new MallUsernamePasswordToken(loginForm.getUserName(), loginForm.getPassword(),
            		loginForm.isRememberMe(), null, loginForm.getLoginType(), loginForm.getCaptcha());
            Subject subject = SecurityUtils.getSubject();
            String profile = environment.getActiveProfiles()[0];
            log.debug("[登录]当前环境为：{}。", profile);
            if (StringUtils.isNotBlank(profile)
//                    && profile.equalsIgnoreCase("prod")
            		&& loginForm.isShowCaptcha()
                    && !CaptchaUtils.matchCaptcha(loginForm.getCaptcha(), subject.getSession())) {
                loginForm.reset();
                result.reject("errors.login.fail", "登录失败，验证码输入错误");
                return loginForm.getLoginType()+loginTemplate;
            }
            subject.login(token);
            /* 踢出非当前的登录 */
            Serializable sessionId = SecurityUtils.getSubject().getSession().getId();
            sessionService.forcedByRepeatLogin(sessionId,"boss", loginForm.getUserName(), null);

            return "redirect:/"+loginForm.getLoginType()+mainTemplate;
        } catch (UnknownAccountException e) {
            loginForm.reset();
            result.reject("errors.login.fail", "登录失败，无此账号");
            return loginForm.getLoginType()+loginTemplate;
        } catch (DisabledAccountException e) {
            loginForm.reset();
            result.reject("errors.login.fail", "登录失败，账号已被锁定");
            return loginForm.getLoginType()+loginTemplate;
        }catch (IncorrectCredentialsException e) {
            String message = "登录失败，密码错误";
            String cacheKey = loginForm.getUserName();
            Cache<String, AtomicInteger> passwordRetryCache = ecm.getCache("passwordRetryCache");
            if (null != passwordRetryCache) {
                int retryNum = (passwordRetryCache.get(cacheKey) == null ? 0
                        : passwordRetryCache.get(cacheKey)).intValue();
                if (retryNum > 1 && retryNum < 5) {
                    message = "密码错误" + retryNum + "次,再输错" + (5 - retryNum) + "次账号将锁定";
                } else if (retryNum == 5) {
                    message = "密码错误5次,账户已锁定! 请一分钟后再试";
                }
            }
            loginForm.reset();
            result.reject("errors.login.fail", message);
            return loginForm.getLoginType()+loginTemplate;
        } catch (ExcessiveAttemptsException e) {
            loginForm.reset();
            result.reject("errors.login.fail", "账号已锁定! 请一分钟后再试");
            return loginForm.getLoginType()+loginTemplate;
        } catch (AuthenticationException e) {
            loginForm.reset();
            result.reject("errors.login.fail", "登录失败，邮箱或密码错误");
            return loginForm.getLoginType()+loginTemplate;
        } catch (Exception e) {
            log.error("", e);
            loginForm.reset();
            result.reject("errors.login.fail", "登录失败，未知错误");
            return loginForm.getLoginType()+loginTemplate;
        }
	}
	
	@GetMapping(value = "/captcha.jpg")
	@Operation(hidden = true)
    public void getCaptcha(HttpServletRequest request,HttpServletResponse response) throws IOException {
        if (HttpUtils.isSpider(request)) // 此请求消耗服务器计算量，所以要检查是爬虫乎
            return;
        HttpUtils.closeCache(response); // 关闭缓存
        Random random = new Random(System.currentTimeMillis()); // 随机数
        String captcha = CaptchaUtils.getRandString(CaptchaUtils.CAPTCHA_LENGTH);
        // save in shiro based session
        SecurityUtils.getSubject().getSession().setAttribute(CaptchaUtils.KEY_CAPTCHA, CaptchaUtils.hashCaptcha(captcha));
        // save end
        BufferedImage bi = CaptchaUtils.getRandCaptchaImage(captcha, random);
        try {
            ImageIO.write(bi, CaptchaUtils.CAPTCHA_MIME_TYPE, response.getOutputStream());
        } catch (IOException e) {
        	request.getSession().removeAttribute(CaptchaUtils.KEY_CAPTCHA);
            throw e;
        }
    }
}
